package com.sgcc.epri.dcloud.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sgcc.epri.dcloud.mapper.dm.*;
import com.sgcc.epri.dcloud.mapper.mpp.AccMapper;
import com.sgcc.epri.dcloud.pojo.*;
import com.sgcc.epri.dcloud.service.ShowTableService;
import com.sgcc.epri.dcloud.util.ChoreUtil;
import com.sgcc.epri.dcloud.util.excel.Column;
import com.sgcc.epri.dcloud.util.excel.ExcelTool;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class ShowTableServiceImpl implements ShowTableService {

    private final Logger log =  LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ShowTableMapper showTableMapper;

    @Autowired
    private TableHeadMapper tableHeadMapper;

    @Autowired
    private IndexBMapper indexBMapper;

    @Autowired
    private CalResultAllMapper calResultAllMapper;

    @Autowired
    private DataMaintenanceMapper dataMaintenanceMapper;

    @Autowired
    private ManagementUnitMapper managementUnitMapper;

    @Autowired
    private TreeMapper treeMapper;

    @Autowired
    private AssetTypeParamCenterMapper assetTypeParamCenterMapper;

    @Autowired
    private IndexIdCenterMapper indexIdCenterMapper;

    @Value("${dm.r-tables}")
    private String dmRTables;

    @Override
    public Result queryTableByTreeId(String treeId, String dataType, String objectIds, String showType, String statisticsType) {
        try {
            Map<String, Object> result = new HashMap<String, Object>();

            // 先判断是否有数据类型和统计维度条件,完整率有数据类型没有统计维度，准确性则相反
            String indexIds = showTableMapper.verifyTableHead(treeId);

            if (null == indexIds) {
                return Result.success("请先配置指标作为二级表头！");
            }

            List<String> ids = Arrays.asList(indexIds.split(","));
            HashSet<String> idsHash = new HashSet<>(ids);
            if (indexIds.contains("1003") && idsHash.size() == 1) {
                result.put("condition", ChoreUtil.conditionMap.get("statisticsType"));
            } else if (indexIds.contains("1003") && idsHash.size() > 1) {

            } else if (!indexIds.contains("1003")) {
                result.put("condition", ChoreUtil.conditionMap.get("dataType"));

            }

            CompletableFuture<List<TreeNode>> tableHead = null;
            CompletableFuture<List<Map<String, Object>>> tableData = null;

            if (!ChoreUtil.isAlpha(statisticsType) && statisticsType.equals("0")) { // 按天统计
                dataType = "1";
                tableHead = getObjectTableHeadDay(treeId, dataType, objectIds);
                tableData = getObjectTableDataDay(treeId, dataType, objectIds, showType);
            } else if (!ChoreUtil.isAlpha(statisticsType) && statisticsType.equals("1")) {// 总数统计
                tableHead = getObjectTableHead(treeId, dataType, objectIds);
                tableData = getObjectTableData(treeId, dataType, objectIds, showType);
            } else if (!ChoreUtil.isAlpha(dataType)){ // 电量或非电量
                tableHead = getObjectTableHead(treeId, dataType, objectIds);
                tableData = getObjectTableData(treeId, dataType, objectIds, showType);
            }else{ // 数据合并展示
                tableHead = getObjectTableHeadMerge(treeId, objectIds);
                tableData = getObjectTableDataMerge(treeId, objectIds, showType);
            }

            // 对象条件
            CompletableFuture<List<Map<String, Object>>> objects = getTreeObjectById(treeId);

            // 等待sql执行
            CompletableFuture.allOf(tableHead, tableData, objects).join();
            // 合计表头及数据处理
            Map<String, Object> map = summationHeadAndData(tableHead.get(), tableData.get(), showType, statisticsType);
            if (map == null) {
                return Result.success("暂无数据");
            }
            result.putAll(map);
            result.put("object", objects.get());
            return Result.success(result);
        }catch (Exception e){
            e.printStackTrace();
            log.error("查询报表失败!"+e);
        }
        return Result.error("查询报表失败");
    }

    @Async("threadPoolTaskExecutor")
    public CompletableFuture<List<Map<String, Object>>> getTreeObjectById(String treeId){
        return CompletableFuture.completedFuture(tableHeadMapper.queryCurrentTreeHead(treeId));
    }

    @Async("threadPoolTaskExecutor")// 按天展示
    public CompletableFuture<List<Map<String, Object>>> getObjectTableDataDay(String treeId, String dataType, String objectIds, String showType) {

        QueryWrapper<CalResultAll> craqw = new QueryWrapper<>();
        craqw.eq("parent_id_tree", treeId);
        String dataTypeJ = dataType.equals("0") ? "nr" : "dky";
        craqw.eq("data_type", dataTypeJ);
        craqw.eq("date_type", "day");
        if (!ChoreUtil.isAlpha(objectIds)) { // 对象类型
            List<String> objectIdList = Arrays.asList(objectIds.split(","));
            craqw.in("object_id", objectIdList);
        }
        craqw.orderByAsc("day_time");
        craqw.select("DAY_TIME, DATASOURCE, SUM(DENOMINATOR) AS DENOMINATOR, SUM(MOLECULE) AS MOLECULE");
        craqw.groupBy("DAY_TIME", "DATASOURCE");
        List<CalResultAll> calResultAlls = calResultAllMapper.selectList(craqw);

        Map<String, Map<String, Map<String, Object>>> datasourceObjectMap = new HashMap<>();

        for (CalResultAll calResultAll : calResultAlls) {
            String datasource = calResultAll.getDatasource();
            Map<String, Map<String, Object>> dom = datasourceObjectMap.get(datasource);
            if(null == dom) dom = new HashMap<String, Map<String, Object>>();
            Map<String, Object> map = dom.get(calResultAll.getDayTime());
            if(map == null) map = new HashMap<>();
            map.put("dataType", "1");
            map.put("datasource", datasource);
            map.put("dateType", "day");
            map.put("fz", calResultAll.getMolecule());
            map.put("fm", calResultAll.getDenominator());
            map.put("indexId", "1003");
            BigDecimal fenzi = new BigDecimal(calResultAll.getMolecule());
            BigDecimal fenmu = new BigDecimal(calResultAll.getDenominator());
            BigDecimal accessRate = fenzi.divide(fenmu, 4, BigDecimal.ROUND_DOWN);
            BigDecimal value = ChoreUtil.one.subtract(accessRate).multiply(ChoreUtil.oneHundred).setScale(2, BigDecimal.ROUND_DOWN);
            String valueS = value.toString().equals("100.00")?"100":value.toString();
            if (showType == null || showType.equals("0")) { // 得分
                map.put("value", valueS);
            }else{// 数值
                map.put("value", calResultAll.getMolecule()+" | "+calResultAll.getDenominator());
            }
            dom.put(calResultAll.getDayTime()+"1003", map);
            datasourceObjectMap.put(datasource, dom);
        }

        QueryWrapper<ManagementUnit> muqw = new QueryWrapper<>();
        muqw.eq("parent_id", treeId);
        muqw.eq("hidden_flag", "1");
        muqw.orderByAsc("sort");

        List<Map<String, Object>> tableData = new ArrayList<>();

        List<ManagementUnit> parent_id = managementUnitMapper.selectList(muqw);
        for (ManagementUnit managementUnit : parent_id) {
            Map<String, Object> map = new HashMap<>();
            map.put("datasource", managementUnit.getName());
            Map<String, Map<String, Object>> data = datasourceObjectMap.get(managementUnit.getDatasource());
            if(data != null) map.putAll(data);
            tableData.add(map);
        }

        return CompletableFuture.completedFuture(tableData);

    }

    @Async("threadPoolTaskExecutor")// 按天展示
    public CompletableFuture<List<TreeNode>> getObjectTableHeadDay(String treeId, String dataType, String objectIds) {
        List<TreeNode> treeNodes = new ArrayList<>();
        treeNodes.add(ChoreUtil.treeNode); // 表头数据源首列

        TreeNode treeNode = treeMapper.selectOne(new QueryWrapper<TreeNode>().eq("id", treeId));
        List<DateTime> rangeToList = DateUtil.rangeToList(DateUtil.parse(treeNode.getCalStartTime()), DateUtil.parse(treeNode.getCalEndTime()), DateField.DAY_OF_YEAR);

        for (DateTime dateTime : rangeToList) {
            TreeNode tns = new TreeNode();
            tns.setId(NumberUtil.generateBySet(1, 999999, 1)[0].longValue());
            tns.setParentId("0");
            tns.setLevel("1");
            tns.setTitle(dateTime.toDateStr());
            tns.setFileType(dateTime.toDateStr());

            if (tns.getChildren() == null) tns.setChildren(new ArrayList<>());

            TreeNode tn = new TreeNode();
            tn.setId(NumberUtil.generateBySet(1, 999999, 1)[0].longValue());
            tn.setParentId(tns.getId()+"");
            tn.setLevel("2");
            tn.setTitle("准确率(ACC)");
            tn.setFileType(tns.getFileType()+"1003");
            tns.getChildren().add(tn);
            treeNodes.add(tns);
        }

        return CompletableFuture.completedFuture(treeNodes);
    }

    /**
     * 合计表头及数据
     * @param tableHead
     * @param tableData
     * @return
     */
    public Map<String, Object> summationHeadAndData(List<TreeNode> tableHead, List<Map<String, Object>> tableData, String showType, String statisticsType){
        Map<String, Object> result = new HashMap<String, Object>();

        if(tableHead.size() < 2) return null;

        // 添加合计表头
        TreeNode tns = new TreeNode();
        tns.setId(NumberUtil.generateBySet(1, 999999, 1)[0].longValue());
        tns.setParentId("0");
        tns.setLevel("1");
        tns.setTitle("总计");
        tns.setFileType("sum");

        if(tns.getChildren() == null) tns.setChildren(new ArrayList<>());

        for (TreeNode node : tableHead) {
            if(node.getChildren() == null ) continue;
            for (TreeNode child : node.getChildren()) {

                boolean valueIs = tns.getChildren().stream().anyMatch(key -> key.getTitle().equals(child.getTitle()));
                if(valueIs) continue;

                TreeNode tnsChild = new TreeNode();
                tnsChild.setId(NumberUtil.generateBySet(1, 999999, 1)[0].longValue());
                tnsChild.setParentId(tns.getId()+"");
                tnsChild.setLevel("2");
                tnsChild.setTitle(child.getTitle());
                tnsChild.setFileType("sum"+child.getFileType().substring(child.getFileType().length()-4));

                tns.getChildren().add(tnsChild);
            }
        }
        tableHead.add(1, tns);
        result.put("tableHead", tableHead);

        // 添加合计数据
        for (Map<String, Object> tableDatum : tableData) {

            Map<String, Map<String, BigDecimal>> calMap = new HashMap<>();
            for (String key : tableDatum.keySet()) {
                if(key.equals("datasource")) continue;
                // 指标code
                String index = key.substring(key.length()-4);

                Map<String, BigDecimal> sbdm = calMap.get(index);
                if(sbdm == null) sbdm = new HashMap<>();

                Map<String, Object> o = (Map<String, Object>) tableDatum.get(key);
                BigDecimal fz = sbdm.get("fz");
                if (fz == null) {
                    fz = new BigDecimal(o.get("fz")+"");
                }else{
                    fz = fz.add(new BigDecimal(o.get("fz")+""));
                }
                sbdm.put("fz", fz);
                BigDecimal fm = sbdm.get("fm");
                if (fm == null) {
                    fm = new BigDecimal(o.get("fm")+"");
                }else{
                    fm = fm.add(new BigDecimal(o.get("fm")+""));
                }
                sbdm.put("fm", fm);

                if (statisticsType != null && statisticsType.equals("0")) {
                    calMap.put("1003", sbdm);
                }else{
                    calMap.put(index, sbdm);
                }

            }

            for (String indexKey : calMap.keySet()) {
                Map<String, BigDecimal> sbm = calMap.get(indexKey);
                BigDecimal fz1 = sbm.get("fz");
                BigDecimal fm1 = sbm.get("fm");
                BigDecimal value = fz1.divide(fm1, 4, BigDecimal.ROUND_DOWN).multiply(ChoreUtil.oneHundred).setScale(2, BigDecimal.ROUND_DOWN);
                if(indexKey.equals("1004")){
                    value = fm1;
                }else if (indexKey.equals("1003")) { // 准确率指标特殊处理
                    value = ChoreUtil.one.subtract(fz1.divide(fm1, 4, BigDecimal.ROUND_DOWN)).multiply(ChoreUtil.oneHundred).setScale(2, BigDecimal.ROUND_DOWN);
                }
                Map<String, Object> sumMap = new HashMap<String, Object>();
                sumMap.put("fz", fz1);
                sumMap.put("fm", fm1);
                sumMap.put("indexId", indexKey);
                if (showType != null && showType.equals("1")) {
                    sumMap.put("value", fz1+" | "+fm1);
                }else{
                    sumMap.put("value", value);
                }
                tableDatum.put("sum"+indexKey, sumMap);
            }
        }

        result.put("tableData", tableData);
        return result;
    }

    /**
     * 对象且电量或非电量表头
     * @param treeId
     * @param dataType
     * @param objectIds
     * @return
     */
    @Async("threadPoolTaskExecutor")
    public CompletableFuture<List<TreeNode>> getObjectTableHead(String treeId, String dataType, String objectIds){
        QueryWrapper<TableHead> thqw = new QueryWrapper<>();
        thqw.isNotNull("object_id");
        thqw.isNotNull("index_names");
        thqw.isNotNull("data_type");
        thqw.eq("parent_id_tree", treeId); // 必填
        thqw.eq("hidden_flag", "1"); // 1表示不隐藏，0则相反
        thqw.orderByAsc("sort");
        String dataTypeJ = dataType.equals("0") ? "nr" : "dky";
        thqw.eq("data_type", dataTypeJ);
        if (!ChoreUtil.isAlpha(objectIds)) { // 对象类型
            List<String> objectIdList = Arrays.asList(objectIds.split(","));
            if (objectIds.equals("0")) {
                QueryWrapper<DataMaintenance> dmqw = new QueryWrapper<>();
                dmqw.in("dky_code", objectIdList);
                List<DataMaintenance> dataMaintenances = dataMaintenanceMapper.selectList(dmqw);
                objectIdList.clear();
                dataMaintenances.forEach(d -> objectIdList.add(d.getNrCode()));
                thqw.in("object_id", objectIdList);
            }else{
                thqw.in("object_id", objectIdList);
            }
        }
        List<TableHead> tableHeads = tableHeadMapper.selectList(thqw);
        List<TreeNode> treeNodes = new ArrayList<>();
        treeNodes.add(ChoreUtil.treeNode); // 表头数据源首列
        for (TableHead tableHead : tableHeads) { // 其余列
            try {
                treeNodes.add(commonLogic(tableHead).get());
            } catch (Exception e) {
                e.printStackTrace();
                log.error("拼接表头时发生错误！"+e);
            }
        }
        return CompletableFuture.completedFuture(treeNodes);
    }

    /**
     * 对象的电量非电量合并表头
     * @param treeId
     * @param objectIds
     * @return
     */
    @Async("threadPoolTaskExecutor")
    public CompletableFuture<List<TreeNode>> getObjectTableHeadMerge(String treeId, String objectIds){

        QueryWrapper<TableHead> thqw1 = new QueryWrapper<>();// 电科院表头数据
        thqw1.isNotNull("object_id");
        thqw1.isNotNull("object_name");
        thqw1.isNotNull("index_names");
        thqw1.isNotNull("data_type");
        thqw1.eq("parent_id_tree", treeId); // 必填
        thqw1.eq("hidden_flag", "1"); // 1表示不隐藏，0则相反
        thqw1.orderByAsc("sort");
        thqw1.eq("data_type", "dky");
        if (!ChoreUtil.isAlpha(objectIds)) { // 对象类型
            List<String> objectIdList = Arrays.asList(objectIds.split(","));
            thqw1.in("object_id", objectIdList);
        }
        QueryWrapper<TableHead> thqw2 = new QueryWrapper<>(); // 南瑞表头数据
        thqw2.isNotNull("object_id");
        thqw2.isNotNull("object_name");
        thqw2.isNotNull("index_names");
        thqw2.isNotNull("data_type");
        thqw2.eq("parent_id_tree", treeId); // 必填
        thqw2.eq("hidden_flag", "1"); // 1表示不隐藏，0则相反
        thqw2.orderByAsc("sort");
        thqw2.eq("data_type", "nr");
        if (!ChoreUtil.isAlpha(objectIds)) { // 对象类型
            List<String> objectIdList = Arrays.asList(objectIds.split(","));
            if (objectIds.equals("0")) {
                QueryWrapper<DataMaintenance> dmqw = new QueryWrapper<>();
                dmqw.in("dky_code", objectIdList);
                List<DataMaintenance> dataMaintenances = dataMaintenanceMapper.selectList(dmqw);
                objectIdList.clear();
                dataMaintenances.forEach(d -> objectIdList.add(d.getNrCode()));
                thqw2.in("object_id", objectIdList);
            }else{
                thqw2.in("object_id", objectIdList);
            }
        }

        List<TableHead> tableHeadsDky = tableHeadMapper.selectList(thqw1);
        List<TableHead> tableHeadsNr = tableHeadMapper.selectList(thqw2);
        Map<String, TableHead> tableNameMapNr = ChoreUtil.getTableNameMapObjH(tableHeadsNr);
        Map<String, DataMaintenance> dataMaintenanceOrc = ChoreUtil.getTableNameMapOrc(dataMaintenanceMapper.selectList(new QueryWrapper<DataMaintenance>().eq("parent_id", "0")));

        List<TreeNode> treeNodes = new ArrayList<>();
        treeNodes.add(ChoreUtil.treeNode); // 表头数据源首列

        for (TableHead tableHeadDky : tableHeadsDky) { // 电科院数据做主循环
            DataMaintenance dataMaintenance = dataMaintenanceOrc.get(tableHeadDky.getObjectId());
            if (dataMaintenance != null) { // 不等于空说明配置了映射关系
                TableHead tableHeadNr = tableNameMapNr.get(dataMaintenance.getNrCode());
                if (tableHeadNr != null) { // 这也不等于空说明配置了具体数据，那么将合并表头
                    TreeNode treeNode = new TreeNode();
                    treeNode.setId(NumberUtil.generateBySet(1, 999999, 1)[0].longValue());
                    treeNode.setLevel("1");
                    treeNode.setParentId("0");
                    treeNode.setFileType(ChoreUtil.toPinyin(tableHeadDky.getObjectName()));
                    treeNode.setTitle(tableHeadDky.getObjectName());
                    treeNode.setAutoFlag(tableHeadDky.getObjectId());

                    HashSet<String> tableName = new HashSet<>();
                    tableName.addAll(Arrays.asList(tableHeadDky.getIndexNames().split(",")));
                    tableName.addAll(Arrays.asList(tableHeadNr.getIndexNames().split(",")));

                    QueryWrapper<IndexB> ibqw = new QueryWrapper<>();
                    ibqw.in("name", new ArrayList<>(tableName));
                    ibqw.orderByAsc("sort");
                    List<IndexB> indexBS = indexBMapper.selectList(ibqw);
                    for (IndexB indexB : indexBS) { // 二级表头
                        TreeNode indexTreeNode = new TreeNode();
                        indexTreeNode.setId(NumberUtil.generateBySet(1, 999999, 1)[0].longValue());
                        indexTreeNode.setLevel("2");
                        indexTreeNode.setParentId(treeNode.getId()+"");
                        indexTreeNode.setFileType(treeNode.getFileType()+indexB.getId());
                        indexTreeNode.setTitle(indexB.getName());
                        if(treeNode.getChildren() == null) treeNode.setChildren(new ArrayList<>());
                        treeNode.getChildren().add(indexTreeNode);
                    }
                    treeNodes.add(treeNode);
                }else{
                    try {
                        treeNodes.add(commonLogic(tableHeadDky).get());
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("拼接表头时发生错误！"+e);
                    }
                }
            } else{
                try {
                    treeNodes.add(commonLogic(tableHeadDky).get());
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("拼接表头时发生错误！"+e);
                }
            }

        }

        ack:for (TableHead tableHead : tableHeadsNr) {// 南瑞数据做副循环
            try {
                for (TableHead head : tableHeadsDky) {
                    if(tableHead.getObjectName().equals(head.getObjectName())) continue ack;
                }
                treeNodes.add(commonLogic(tableHead).get());
            } catch (Exception e) {
                e.printStackTrace();
                log.error("拼接表头时发生错误！"+e);
            }
        }

        return CompletableFuture.completedFuture(treeNodes);
    }

    /**
     * 部分相同逻辑
     * @param tableHead
     * @return
     */
    @Async("threadPoolTaskExecutor")
    public CompletableFuture<TreeNode> commonLogic(TableHead tableHead){
        TreeNode treeNode = new TreeNode();
        treeNode.setId(NumberUtil.generateBySet(1, 999999, 1)[0].longValue());
        treeNode.setLevel("1");
        treeNode.setParentId("0");
        treeNode.setFileType(ChoreUtil.toPinyin(tableHead.getObjectName()));
        treeNode.setTitle(tableHead.getObjectName());

        QueryWrapper<IndexB> ibqw = new QueryWrapper<>();
        ibqw.in("name", Arrays.asList(tableHead.getIndexNames().split(",")));
        ibqw.orderByAsc("sort");
        List<IndexB> indexBS = indexBMapper.selectList(ibqw);
        for (IndexB indexB : indexBS) { // 二级表头
            TreeNode indexTreeNode = new TreeNode();
            indexTreeNode.setId(NumberUtil.generateBySet(1, 999999, 1)[0].longValue());
            indexTreeNode.setLevel("2");
            indexTreeNode.setParentId(treeNode.getId()+"");
            indexTreeNode.setFileType(treeNode.getFileType()+indexB.getId());
            indexTreeNode.setTitle(indexB.getName());
            indexTreeNode.setAutoFlag(tableHead.getObjectId());
            if(treeNode.getChildren() == null) treeNode.setChildren(new ArrayList<>());
            treeNode.getChildren().add(indexTreeNode);
        }
        return CompletableFuture.completedFuture(treeNode);
    }

    /**
     * 对象维度的总数
     * @param treeId
     * @param dataType
     * @param objectIds
     * @return
     */
    @Async("threadPoolTaskExecutor")
    public CompletableFuture<List<Map<String, Object>>> getObjectTableData(String treeId, String dataType, String objectIds, String showType){

        QueryWrapper<CalResultAll> cralqw = new QueryWrapper<>();
        cralqw.eq("parent_id_tree", treeId);
        String dataTypeJ = dataType.equals("0") ? "nr" : "dky";
        cralqw.eq("data_type", dataTypeJ);
        cralqw.eq("date_type", "allday");
        if (!ChoreUtil.isAlpha(objectIds)) { // 对象类型
            List<String> objectIdList = Arrays.asList(objectIds.split(","));
            if (objectIds.equals("0")) {
                QueryWrapper<DataMaintenance> dmqw = new QueryWrapper<>();
                dmqw.in("dky_code", objectIdList);
                List<DataMaintenance> dataMaintenances = dataMaintenanceMapper.selectList(dmqw);
                objectIdList.clear();
                dataMaintenances.forEach(d -> objectIdList.add(d.getNrCode()));
                cralqw.in("object_id", objectIdList);
            }else{
                cralqw.in("object_id", objectIdList);
            }
        }

        List<CalResultAll> calResultAlls = calResultAllMapper.selectList(cralqw);

        Map<String, Object> tableNameMap = ChoreUtil.getTableNameMap(calResultAllMapper.queryObjectNameAll());

        // 数据源 -> 字段名 -> 属性值
        Map<String, Map<String, Map<String, Object>>> datasourceObjectMap = new HashMap<>();

        for (CalResultAll calResultAll : calResultAlls) {
            Map<String, Map<String, Object>> mapB = datasourceObjectMap.get(calResultAll.getDatasource());
            if(mapB == null) mapB = new HashMap<>();
            String key = ChoreUtil.toPinyin(tableNameMap.get(calResultAll.getObjectId())+"")+calResultAll.getParentIdIndex();
            Map<String, Object> mapM = mapB.get(key);
            if(mapM == null) mapM = new HashMap<>();
            if(calResultAll.getParentIdIndex().equals("1004")){
                mapM.put("value", calResultAll.getDenominator());
            }else if (showType == null || showType.equals("0")) { // 得分
                mapM.put("value", calResultAll.getValue());
            }else{// 数值
                mapM.put("value", calResultAll.getMolecule()+" | "+calResultAll.getDenominator());
            }
            mapM.put("parentIdTableHead",calResultAll.getParentIdTablehead());
            mapM.put("indexId", calResultAll.getParentIdIndex());
            mapM.put("objectId", calResultAll.getObjectId());
            mapM.put("datasourceId", calResultAll.getDatasource());
            mapM.put("dataType", dataType);
            mapM.put("fz", calResultAll.getMolecule());
            mapM.put("fm", calResultAll.getDenominator());
            if (showType == null || showType.equals("0")) { // 得分
                mapM.put("dateType", "dayall");
            }else{// 数值
                mapM.put("dateType", "day");
            }
            mapB.put(key, mapM);
            datasourceObjectMap.put(calResultAll.getDatasource(), mapB);
        }

        QueryWrapper<ManagementUnit> muqw = new QueryWrapper<>();
        muqw.eq("parent_id", treeId);
        muqw.eq("hidden_flag", "1");
        muqw.orderByAsc("sort");

        List<Map<String, Object>> tableData = new ArrayList<>();

        List<ManagementUnit> parent_id = managementUnitMapper.selectList(muqw);
        for (ManagementUnit managementUnit : parent_id) {
            Map<String, Object> map = new HashMap<>();
            map.put("datasource", managementUnit.getName());
            Map<String, Map<String, Object>> data = datasourceObjectMap.get(managementUnit.getDatasource());
            if(data != null) map.putAll(data);
            tableData.add(map);
        }

        return CompletableFuture.completedFuture(tableData);
    }

    /**
     * 对象维度电量非电量合并数据
     * @param treeId
     * @param objectIds
     * @param showType
     * @return
     */
    @Async("threadPoolTaskExecutor")
    public CompletableFuture<List<Map<String, Object>>> getObjectTableDataMerge(String treeId, String objectIds, String showType){

        QueryWrapper<CalResultAll> cralqwDky = new QueryWrapper<>();
        cralqwDky.eq("parent_id_tree", treeId);
        cralqwDky.eq("data_type", "dky");
        cralqwDky.eq("date_type", "allday");
        if (!ChoreUtil.isAlpha(objectIds)) { // 对象类型
            List<String> objectIdList = Arrays.asList(objectIds.split(","));
            cralqwDky.in("object_id", objectIdList);
        }
        QueryWrapper<CalResultAll> cralqwNr = new QueryWrapper<>();
        cralqwNr.eq("parent_id_tree", treeId);
        cralqwNr.eq("data_type", "nr");
        cralqwNr.eq("date_type", "allday");
        if (!ChoreUtil.isAlpha(objectIds)) { // 对象类型
            List<String> objectIdList = Arrays.asList(objectIds.split(","));
            if (objectIds.equals("0")) {
                QueryWrapper<DataMaintenance> dmqw = new QueryWrapper<>();
                dmqw.in("dky_code", objectIdList);
                List<DataMaintenance> dataMaintenances = dataMaintenanceMapper.selectList(dmqw);
                objectIdList.clear();
                dataMaintenances.forEach(d -> objectIdList.add(d.getNrCode()));
                cralqwNr.in("object_id", objectIdList);
            }else{
                cralqwNr.in("object_id", objectIdList);
            }
        }
        List<CalResultAll> calResultAllsDky = calResultAllMapper.selectList(cralqwDky);
        List<CalResultAll> calResultAllsNr = calResultAllMapper.selectList(cralqwNr);
        List<DataMaintenance> dmm = dataMaintenanceMapper.selectList(new QueryWrapper<DataMaintenance>().eq("parent_id", "0"));
        Map<String, CalResultAll> tableNameMapObjD = ChoreUtil.getTableNameMapObjD(calResultAllsNr, dmm);
        Map<String, DataMaintenance> dataMaintenanceOrc = ChoreUtil.getTableNameMapOrc(dataMaintenanceMapper.selectList(new QueryWrapper<DataMaintenance>().eq("parent_id", "0")));

        Map<String, Object> tableNameMap = ChoreUtil.getTableNameMap(calResultAllMapper.queryObjectNameAll());
        // 数据源 -> 字段名 -> 属性值
        Map<String, Map<String, Map<String, Object>>> datasourceObjectMap = new HashMap<>();

        // 副循环中略过元素
        List<CalResultAll> selfLoopSkip = new ArrayList<>();

        for (CalResultAll calResultAll : calResultAllsDky) { // 电科院数据做主循环
            DataMaintenance dataMaintenance = dataMaintenanceOrc.get(calResultAll.getObjectId());
            CalResultAll calResultAllOrc = tableNameMapObjD.get(calResultAll.getObjectId()+calResultAll.getDatasource()+calResultAll.getParentIdIndex());

            if(dataMaintenance != null && calResultAllOrc != null) {// 不等于空说明配置了映射关系,合并数据
                selfLoopSkip.add(calResultAllOrc);
                Map<String, Map<String, Object>> mapB = datasourceObjectMap.get(calResultAll.getDatasource());
                if (mapB == null) mapB = new HashMap<>();
                String key = ChoreUtil.toPinyin(tableNameMap.get(calResultAll.getObjectId()) + "") + calResultAll.getParentIdIndex();
                Map<String, Object> mapM = mapB.get(key);
                if (mapM == null) mapM = new HashMap<>();

                BigDecimal fzd = new BigDecimal(calResultAll.getMolecule());
                BigDecimal fmd = new BigDecimal(calResultAll.getDenominator());
                BigDecimal fzn = new BigDecimal(calResultAllOrc.getMolecule());
                BigDecimal fmn = new BigDecimal(calResultAllOrc.getDenominator());
                BigDecimal fz = fzd.add(fzn);
                BigDecimal fm = fmd.add(fmn);
                BigDecimal closeAnAccount = fz.divide(fm, 4, BigDecimal.ROUND_DOWN).multiply(ChoreUtil.oneHundred).setScale(2, BigDecimal.ROUND_DOWN);
                if(calResultAll.getParentIdIndex().equals("1004")){
                    mapM.put("value", fm);
                }else if (showType == null || showType.equals("0")) { // 得分
                    mapM.put("value", closeAnAccount);
                }else{// 数值
                    mapM.put("value", fz+" | "+fm);
                }
                mapM.put("dataType", "1");
                mapM.put("indexId", calResultAll.getParentIdIndex());
                mapM.put("objectId", calResultAll.getObjectId());
                mapM.put("datasourceId", calResultAll.getDatasource());
                mapM.put("parentIdTableHead",calResultAll.getParentIdTablehead());
                mapM.put("fz", fz);
                mapM.put("fm", fm);
                if (showType == null || showType.equals("0")) { // 得分
                    mapM.put("dateType", "dayall");
                }else{// 数值
                    mapM.put("dateType", "day");
                }
                mapB.put(key, mapM);
                datasourceObjectMap.put(calResultAll.getDatasource(), mapB);
            }else{
                getObjectTableDataMergeConcubine(datasourceObjectMap, calResultAll, tableNameMap, showType, "1");
            }

        }

        for (CalResultAll calResultAll : calResultAllsNr) { // 南瑞数据做副循环
            if(selfLoopSkip.contains(calResultAll)) continue;
            getObjectTableDataMergeConcubine(datasourceObjectMap, calResultAll, tableNameMap, showType, "0");
        }

        QueryWrapper<ManagementUnit> muqw = new QueryWrapper<>();
        muqw.eq("parent_id", treeId);
        muqw.eq("hidden_flag", "1");
        muqw.orderByAsc("sort");

        List<Map<String, Object>> tableData = new ArrayList<>();

        List<ManagementUnit> parent_id = managementUnitMapper.selectList(muqw);
        for (ManagementUnit managementUnit : parent_id) {
            Map<String, Object> map = new HashMap<>();
            map.put("datasource", managementUnit.getName());
            Map<String, Map<String, Object>> data = datasourceObjectMap.get(managementUnit.getDatasource());
            if(data != null) map.putAll(data);
            tableData.add(map);
        }

        return CompletableFuture.completedFuture(tableData);
    }

    public void getObjectTableDataMergeConcubine(Map<String, Map<String, Map<String, Object>>> datasourceObjectMap, CalResultAll calResultAll, Map<String, Object> tableNameMap, String showType, String dataType){
        Map<String, Map<String, Object>> mapB = datasourceObjectMap.get(calResultAll.getDatasource());
        if(mapB == null) mapB = new HashMap<>();
        String key = ChoreUtil.toPinyin(tableNameMap.get(calResultAll.getObjectId())+"")+calResultAll.getParentIdIndex();
        Map<String, Object> mapM = mapB.get(key);
        if(mapM == null) mapM = new HashMap<>();


        if (showType == null || showType.equals("0")) { // 得分
            mapM.put("value", calResultAll.getValue());
        }else{// 数值
            mapM.put("value", calResultAll.getMolecule()+" | "+calResultAll.getDenominator());
        }
        mapM.put("dataType", dataType);
        mapM.put("indexId", calResultAll.getParentIdIndex());
        mapM.put("parentIdTableHead",calResultAll.getParentIdTablehead());
        mapM.put("objectId", calResultAll.getObjectId());
        mapM.put("datasourceId", calResultAll.getDatasource());
        mapM.put("fz", calResultAll.getMolecule());
        mapM.put("fm", calResultAll.getDenominator());
        if (showType == null || showType.equals("0")) { // 得分
            mapM.put("dateType", "dayall");
        }else{// 数值
            mapM.put("dateType", "day");
        }
        mapB.put(key, mapM);
        datasourceObjectMap.put(calResultAll.getDatasource(), mapB);
    }


    @Override
    public void excelTable(String treeId, String dataType, String objectIds, String showType, String statisticsType, HttpServletRequest request, HttpServletResponse response) {
        try{

            Result result = queryTableByTreeId(treeId, dataType, objectIds, showType, statisticsType);

            if (result == null || result.getData() == null) {
                log.error("导出过程中需要用到的参数为空！");
                return;
            }

            Map<String, Object> data = (Map<String, Object>) result.getData();
            List<Map<String, Object>> dataDivision = (List<Map<String, Object>>) data.get("tableData");

            boolean flag = false; // 是否要将分子分母列拆开
            if (dataDivision != null && dataDivision.size() >= 0) {
                start:for (Map<String, Object> map : dataDivision) {
                    if (map != null && map.size() > 2) {
                        for (String key : map.keySet()) {
                            Object o = map.get(key);
                            if (o instanceof Map) {
                                Map om = (Map) o;
                                Object value = om.get("value");
                                if (value.toString().contains("|")) {
                                    flag = true;
                                    break start;
                                }
                            }
                        }
                    }
                }
            }

            List<Map<String,String>> tableHead = new ArrayList<>();

            for (TreeNode treeNode : (List<TreeNode>) data.get("tableHead")) {
                Map<String, String> map = new HashMap<>();
                map.put("id", treeNode.getId()+"");
                map.put("parentId", treeNode.getParentId());
                map.put("title", treeNode.getTitle());
                map.put("fileType", treeNode.getFileType());
                tableHead.add(map);
                dfs(treeNode, tableHead, flag);
            }

            if(flag){
                for (Map<String, Object> map : dataDivision) {

                    Map<String, Map<String, Object>> temp = new HashMap<>();

                    for (String key : map.keySet()) {
                        if(key.equals("datasource")) continue;

                        Map m = (Map) map.get(key);

                        Map<String, Object> newMapFz = new HashMap<>();
                        newMapFz.put("value", m.get("fz"));
                        temp.put(key+"fz", newMapFz);
                        Map<String, Object> newMapFm = new HashMap<>();
                        newMapFm.put("value", m.get("fm"));
                        temp.put(key+"fm", newMapFm);
                    }
                    map.putAll(temp);
                }
            }

            ExcelTool excelTool = new ExcelTool("指标统计",20,20);
            List<Column> titleData=excelTool.columnTransformer(tableHead,"id","parentId","title","fileType","0");
            XSSFWorkbook hssfWorkbook = excelTool.exportWorkbook(titleData, dataDivision, true);

            // 输出Excel文件
            OutputStream outputStream = response.getOutputStream();
            // 下面几行是为了解决文件名乱码的问题
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("指标统计", "UTF8") + ".xlsx");
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.setHeader("Pragma", "no-cache");//关闭缓存
            response.setHeader("Cache-Control", "no-cache");//关闭缓存
            response.setDateHeader("Expires", 0);//为了让浏览器不要缓存页面，也可以利用Expires实体报关域，设置为0
            hssfWorkbook.write(outputStream);
            outputStream.close();

        }catch (Exception e){
            e.printStackTrace();
            log.error("导出失败！");
        }
    }

    /**
     * 递归调用
     */
    private void dfs(TreeNode node, List<Map<String,String>> tableHead, boolean flag) {
        if (node == null || node.getChildren() == null) return;
        for (TreeNode treeNode : node.getChildren()) {
            Map<String, String> map = new HashMap<>();
            map.put("id", treeNode.getId()+"");
            map.put("parentId", treeNode.getParentId());
            map.put("title", treeNode.getTitle());
            map.put("fileType", treeNode.getFileType());
            tableHead.add(map);
            if (flag) division(tableHead, map);
            dfs(treeNode, tableHead, flag); // 递归访问每一个子节点
        }
    }

    public void division(List<Map<String,String>> tableHead, Map<String, String> map){
        Map<String, String> map1 = new HashMap<>();
        map1.put("id", NumberUtil.generateBySet(1, 999999, 1)[0].longValue()+"");
        map1.put("parentId", map.get("id"));
        map1.put("title", "分子");
        map1.put("fileType", map.get("fileType")+"fz");
        tableHead.add(map1);

        Map<String, String> map2 = new HashMap<>();
        map2.put("id", NumberUtil.generateBySet(1, 999999, 1)[0].longValue()+"");
        map2.put("parentId", map.get("id"));
        map2.put("title", "分母");
        map2.put("fileType", map.get("fileType")+"fm");
        tableHead.add(map2);
    }


//    NumberUtil.generateBySet(1, 999999, 1)[0].longValue()
    @Autowired
    private IntegralityOneLevelMapper integralityOneLevelMapper;

    @Autowired
    private IntegralityTwoLevelMapper integralityTwoLevelMapper;

    @Autowired
    private AccuracyRateContentMapper accuracyRateContentMapper;

    @Autowired
    private AccMapper accMapper;

    @Override
    public Result particulars(String treeId, String datasource, String indexId,
                              String objectId, String dataType, String dateType,
                              String contentType, Integer page, Integer limit,
                              String showType, String tableHeadId, String assetId,
                              String datasourceName, String dayTime, String assessmentInterval) {
        try{
            Map<String, Object> result = new HashMap<>();

            if (!ChoreUtil.isAlpha(dataType) && dataType.equals("0")) {
                return Result.error("电量无详情数据");
            }

            if ("1001,1002,1004".contains(indexId)) {// 完整率详情
                if (contentType.equals("101")) { // 完整率一级详情
                    showType = showType.equals("0") ? "as" : "ls";
                    PageHelper.startPage(page, limit);
                    List<Map<String, Object>> integralityOneLevels =  integralityOneLevelMapper.queryIntegratedRate(treeId, datasource, indexId, objectId, dataType, dateType, contentType, showType, tableHeadId);
                    PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(integralityOneLevels);
                    result.put("data", pageInfo);
                    result.put("head", ChoreUtil.dynamicHeader.get("integralityOneList"));
                    return Result.success(result);
                }else if (contentType.equals("102")){ // 完整率二级详情
                    Page<IntegralityTwoLevel> pl = new Page<>(page, limit);
                    QueryWrapper<IntegralityTwoLevel> iolqw = new QueryWrapper<>();
                    iolqw.eq("parent_id_tree", treeId);
                    iolqw.eq("parent_id_table_head", tableHeadId);
                    iolqw.eq("datasource", datasource);
                    iolqw.eq("index_id", indexId);
                    iolqw.eq("object_id", objectId);
                    iolqw.eq("data_type", "dky");
                    iolqw.eq("asset_id", assetId);
                    if(!ChoreUtil.isAlpha(showType) && showType.equals("0")) {// 得分
                        iolqw.select("DEV_ID, DEV_NAME, EXAMINATION_TIME, BEFORE_TIME, VALUE");
                    } else if (!ChoreUtil.isAlpha(showType) && showType.equals("1")){ // 数值
                        iolqw.select("DEV_ID, DEV_NAME, EXAMINATION_TIME, BEFORE_TIME, CONCAT(MOLECULE, ' | ', DENOMINATOR) AS VALUE");
                    }
                    Page<IntegralityTwoLevel> integralityTwoLevelPage = integralityTwoLevelMapper.selectPage(pl, iolqw);
                    integralityTwoLevelPage.getRecords().forEach(record -> record.setDatasourceName(datasourceName));

                    result.put("data", integralityTwoLevelPage);
                    result.put("head", ChoreUtil.dynamicHeader.get("integralityOneList"+indexId));
                    return Result.success(result);
                }
            } else if ("1003".contains(indexId)) {// 准确率详情

                if (contentType.equals("101")) { // 准确率一级详情
                    Page<AccuracyRateContent> pl = new Page<>(page, limit);
                    QueryWrapper<AccuracyRateContent> arcq = new QueryWrapper<>();
                    arcq.eq("parent_id_tree", treeId);
                    arcq.eq("datasource", datasource);

                    if (dateType.equals("1")) { // 总数
                        arcq.eq("object_id", objectId);
                        arcq.eq("parent_id_table_head", tableHeadId);
                        arcq.select("ASSET_NAME, ASSET_ID, SUM(DENOMINATOR) AS DENOMINATOR, SUM(MOLECULE) AS MOLECULE, RELEVANCE_RULE_NUM");
                        arcq.groupBy("ASSET_NAME", "ASSET_ID", "RELEVANCE_RULE_NUM");
                    } else if (dateType.equals("0")) { // 单天
                        arcq.select("ASSET_NAME, ASSET_ID, DENOMINATOR, MOLECULE, RELEVANCE_RULE_NUM, VALUE");
                        arcq.eq("day_time", dayTime);
                    }
                    Page<AccuracyRateContent> accuracyRateContentPage = accuracyRateContentMapper.selectPage(pl, arcq);
                    for (AccuracyRateContent record : accuracyRateContentPage.getRecords()) {
                        BigDecimal fz1 = new BigDecimal(record.getMolecule());
                        BigDecimal fm1 = new BigDecimal(record.getDenominator());
                        BigDecimal value = ChoreUtil.one.subtract(fz1.divide(fm1, 4, BigDecimal.ROUND_DOWN)).multiply(ChoreUtil.oneHundred).setScale(2, BigDecimal.ROUND_DOWN);
                        record.setValue(value.toString());
                    }
                    result.put("head", ChoreUtil.dynamicHeader.get("accuracyRateContent1003"));
                    result.put("data", accuracyRateContentPage);
                } else if (contentType.equals("102")) { // 准确率二级详情
                    String objectType = accMapper.queryObjectNameById(objectId);
                    ArrayList<String> datasourceIds = new ArrayList<>();
                    datasourceIds.add(datasource);
                    String assetType = assetId;
                    String problemType = "";
                    String dt = assessmentInterval;
                    String search = "";

                    CompletableFuture<List<Map<String, Object>>> listCompletableFuture = CompletableFuture.completedFuture(accMapper.queryContentTwo(objectType, datasourceIds, assetType, problemType, dt, search, limit, (page - 1)));
                    CompletableFuture<Integer> countCompletableFuture = CompletableFuture.completedFuture(accMapper.queryContentTwoCount(objectType, datasourceIds, assetType, problemType, dt, search, limit, (page - 1)));

                    CompletableFuture.allOf(listCompletableFuture, countCompletableFuture).join();

                    result.put("head", ChoreUtil.dynamicHeader.get("accuracyRateContent1003TwoLevel"));
                    result.put("data", listCompletableFuture.get());
                    result.put("total", countCompletableFuture.get());
                }

                return Result.success(result);
            }

        }catch (Exception e){
            e.printStackTrace();
            log.error("指标详情获取失败");
        }
        return Result.error("指标详情获取失败");
    }

    @Override
    public void generateReports(String treeId, HttpServletRequest request, HttpServletResponse response) {
        try{

            XWPFDocument document = new XWPFDocument();

            XWPFParagraph paragraph = document.createParagraph();
            paragraph.setAlignment(ParagraphAlignment.CENTER);
            XWPFRun run = paragraph.createRun();
            run.setText("运行数据");// 大标题
            run.setFontSize(22);
            run.setFontFamily("方正小标宋简体");

            TreeNode treeNode = treeMapper.selectOne(new QueryWrapper<TreeNode>().eq("id", treeId));
            if(treeNode == null || treeNode.getCalEndTime() ==null){
                log.error("报告生成过程中需要用到的考核结束时间参数为空！");
                return;
            }

            QueryWrapper<TableHead> thqw = new QueryWrapper<>();
            thqw.eq("parent_id_tree", treeId);
//            thqw.eq("data_type", "dky");
            thqw.eq("hidden_flag", "1");
            thqw.orderByAsc("sort");
            List<TableHead> tableHeads = tableHeadMapper.selectList(thqw); // 电科院表头
            if (tableHeads == null || tableHeads.size() == 0){
                log.error("没有配置表头，无法生成报告");
                return;
            }

            // 运行数据概括部分-第一段
            CompletableFuture<StringBuffer> generalizeFirstStage = getGeneralizeFirstStage(treeNode, tableHeads);
            // 运行数据概括部分-第二段
            CompletableFuture<StringBuffer> generalizeVerseTwo = getGeneralizeVerseTwo(tableHeads, treeId);
            // 等待执行
            CompletableFuture.allOf(generalizeFirstStage, generalizeVerseTwo).join();

            XWPFParagraph paragraphFiveFirstStage = document.createParagraph();
            paragraphFiveFirstStage.setAlignment(ParagraphAlignment.LEFT);
            paragraphFiveFirstStage.setFirstLineIndent(650);// 首行缩进
            XWPFRun runFiveFirstStage = paragraphFiveFirstStage.createRun();
            runFiveFirstStage.setText(generalizeFirstStage.get().toString());
            runFiveFirstStage.setFontSize(16);
            runFiveFirstStage.setFontFamily("方正仿宋简体");

            XWPFParagraph paragraphFiveVerseTwo = document.createParagraph();
            paragraphFiveVerseTwo.setAlignment(ParagraphAlignment.LEFT);
            paragraphFiveVerseTwo.setFirstLineIndent(650);// 首行缩进
            XWPFRun runFiveVerseTwo = paragraphFiveVerseTwo.createRun();
            runFiveVerseTwo.setText(generalizeVerseTwo.get().toString());
            runFiveVerseTwo.setFontSize(16);
            runFiveVerseTwo.setFontFamily("方正仿宋简体");

            Result result = queryTableByTreeId(treeId, null, null, null, null);

            Map<String, Object> data = (Map<String, Object>) result.getData();

            List<Map<String, Object>> tableData = (List<Map<String, Object>>) data.get("tableData");
            List<TreeNode> tableHead = (List<TreeNode>) data.get("tableHead");

            for (int i = 2; i < tableHead.size(); i++) {

                XWPFParagraph paragraphFour = document.createParagraph();
                XWPFRun runFour = paragraphFour.createRun();
                paragraphFour.setAlignment(ParagraphAlignment.LEFT);
                paragraphFour.setFirstLineIndent(0);// 首行缩进
                runFour.setText((i-1)+"."+tableHead.get(i).getTitle()+"类数据情况");
                runFour.setFontSize(16);
                runFour.setFontFamily("方正仿宋简体");
                runFour.setBold(true);
                CTP ctpFour = paragraphFour.getCTP();// 四级大纲
                ctpFour.addNewPPr().addNewOutlineLvl().setVal(BigInteger.valueOf(4));

                List<TreeNode> children = tableHead.get(i).getChildren();
                for (TreeNode child : children) {
                    List<String> array100 = new ArrayList<String>();
                    List<String> array90 = new ArrayList<String>();
                    List<String> array90Down = new ArrayList<String>();
                    for (Map<String, Object> tableDatum : tableData) {
                        for (String key : tableDatum.keySet()) {// 指标维度
                            if (!key.startsWith("sum") && key.endsWith(child.getFileType().substring(child.getFileType().length()-4))) {
                                Map<String, Object> map = (Map<String, Object>) tableDatum.get(key);
                                String objectId = map.get("objectId").toString();
                                if(!objectId.equals(child.getAutoFlag())) continue;
                                Object valueO = map.get("value");
                                double value = Double.parseDouble(valueO+"");
                                if(ChoreUtil.isAlpha(tableDatum.get("datasource")+""))continue;
                                if (value == 100) {
                                    array100.add(tableDatum.get("datasource")+"");
                                } else if (value >= 90) {
                                    array90.add(tableDatum.get("datasource")+"");
                                } else {
                                    array90Down.add(tableDatum.get("datasource")+"");
                                }
                            }
                        }
                    }
                    StringBuffer sbf = new StringBuffer();
                    XWPFParagraph paragraphB = document.createParagraph();
                    XWPFRun runB = paragraphB.createRun();
                    paragraphB.setAlignment(ParagraphAlignment.LEFT);
                    paragraphB.setFirstLineIndent(650);// 首行缩进
                    runB.setText(child.getTitle());
                    runB.setFontSize(16);
                    runB.setFontFamily("方正仿宋简体");
                    runB.setBold(true);
                    sbf.append("达到100%的单位有");
                    if (array100.size() == 0) {
                        sbf.append("0家；");
                    }else{
                        sbf.append(array100.size()).append("家，分别为");
                        for (int j = 0; j < array100.size(); j++) {
                            if(ChoreUtil.isAlpha(array100.get(j)))continue;
                            sbf.append(array100.get(j), 0, 2);
                            if(j != array100.size()-1) {
                                sbf.append("、");
                            }else {
                                sbf.append("；");
                            }
                        }
                    }

                    sbf.append("达到90%的单位有");
                    if (array90.size() == 0) {
                        sbf.append("0家；");
                    }else{
                        sbf.append(array90.size()).append("家，分别为");
                        for (int k = 0; k < array90.size(); k++) {
                            if(ChoreUtil.isAlpha(array90.get(k)))continue;
                            sbf.append(array90.get(k), 0, 2);
                            if(k != array90.size()-1) {
                                sbf.append("、");
                            }else {
                                sbf.append("；");
                            }
                        }
                    }

                    sbf.append("未达到90%的单位有");
                    if (array90Down.size() == 0) {
                        sbf.append("0家。");
                    }else{
                        sbf.append(array90Down.size()).append("家，分别为");
                        for (int l = 0; l < array90Down.size(); l++) {
                            if(ChoreUtil.isAlpha(array90Down.get(l)))continue;
                            sbf.append(array90Down.get(l), 0, 2);
                            if(l != array90Down.size()-1) {
                                sbf.append("、");
                            }else {
                                sbf.append("。");
                            }
                        }
                    }

                    XWPFRun runFive = paragraphB.createRun();
                    runFive.setText(sbf.toString());
                    runFive.setFontSize(16);
                    runFive.setFontFamily("方正仿宋简体");
                }

            }

            response.setContentType("application/vnd.ms-docx");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("运行数据", "UTF8") + ".docx");
            response.setHeader("Pragma", "no-cache");//关闭缓存
            response.setHeader("Cache-Control", "no-cache");//关闭缓存
            response.setDateHeader("Expires", 0);
            ServletOutputStream opt = response.getOutputStream();
            document.write(opt);
            opt.close();
            document.close();

        }catch (Exception e){
            e.printStackTrace();
            log.error("生成报告失败!"+e);
        }
    }

    /**
     * 生成文档-概览-第一段
     * @param treeNode
     * @param tableHeads
     * @return
     */
    @Async("threadPoolTaskExecutor")
    public CompletableFuture<StringBuffer> getGeneralizeFirstStage(TreeNode treeNode, List<TableHead> tableHeads){
        StringBuffer generalizeFirstStage = new StringBuffer();
        generalizeFirstStage.append("截止");
        if (treeNode.getCalEndTime() == null || treeNode.getCalEndTime().equals("")) {
            generalizeFirstStage.append("到该报告的统计生成时刻");
        }else{
            generalizeFirstStage.append(treeNode.getCalEndTime(), 0, 5).append("年");
            generalizeFirstStage.append(treeNode.getCalEndTime(), 6, 8).append("月");
            generalizeFirstStage.append(treeNode.getCalEndTime(), 9, 11).append("日");
        }
        generalizeFirstStage.append("，开展");
        for (int i = 0; i < tableHeads.size(); i++) {
            generalizeFirstStage.append(tableHeads.get(i).getObjectName()).append("（");
            generalizeFirstStage.append(tableHeads.get(i).getAssetTypeNames().replaceAll(",", "、")).append("）");
            if(i != tableHeads.size()-1) generalizeFirstStage.append("、");
        }
        generalizeFirstStage.append("共计");
        List<Long> names = tableHeads.stream().map(TableHead::getId).collect(Collectors.toList());
        QueryWrapper<AssetTypeParamCenter> atpcqw = new QueryWrapper<>();
        atpcqw.select("distinct tablehead_id, asset_id");
        atpcqw.in("tablehead_id", names);
        List<AssetTypeParamCenter> assetTypes = assetTypeParamCenterMapper.selectList(atpcqw); // 所有表头下的参数
        generalizeFirstStage.append(assetTypes.size()).append("类的历史数据治理，总计");
        List<String> assetId = assetTypes.stream().map(AssetTypeParamCenter::getAssetId).collect(Collectors.toList());
        Integer assetAllCount = assetTypeParamCenterMapper.queryAssetAllCount(assetId, Arrays.asList(dmRTables.split(","))); // 所有参数
        generalizeFirstStage.append(assetAllCount).append("个资产。");
        return CompletableFuture.completedFuture(generalizeFirstStage);
    }

    /**
     * 生成文档-概览-第二段
     * @param tableHeads
     * @param treeId
     * @return
     */
    @Async("threadPoolTaskExecutor")
    public CompletableFuture<StringBuffer> getGeneralizeVerseTwo(List<TableHead> tableHeads, String treeId){
        StringBuffer generalizeVerseTwo = new StringBuffer();
        Map<String, Object> tableNameMap = ChoreUtil.getTableNameMap(tableHeadMapper.queryCodeNameOrc());
        generalizeVerseTwo.append("从对象类型上看，具体包括");
        for (int i = 0; i < tableHeads.size(); i++) {
            Long electricPower = 0l; // 电力
            Long electricCQuantity = 0l; // 电量
            Long sum = 0l;
            generalizeVerseTwo.append(tableHeads.get(i).getObjectName());
            QueryWrapper<AssetTypeParamCenter> assetTypeParamCenterQueryWrapper = new QueryWrapper<>();
            assetTypeParamCenterQueryWrapper.select("distinct tablehead_id, asset_id");
            assetTypeParamCenterQueryWrapper.eq("tablehead_id", tableHeads.get(i).getId());
            List<AssetTypeParamCenter> tableHeadIds = assetTypeParamCenterMapper.selectList(assetTypeParamCenterQueryWrapper);
            generalizeVerseTwo.append(tableHeadIds.size()).append("类");
            if (tableHeadIds.size() > 0 && tableHeads.get(i).getDataType().equals("dky")) {
                Object ot = tableNameMap.get(tableHeads.get(i).getObjectId());
                electricPower = assetTypeParamCenterMapper.queryCountByAsset(ot, tableHeadIds.stream().map(AssetTypeParamCenter::getAssetId).collect(Collectors.toList()));
            }
            if (tableHeadIds.size() > 0 && tableHeads.get(i).getDataType().equals("nr")) {
                if (tableHeads.get(i).getObjectId().equals("1")) {
                    electricCQuantity = Long.parseLong(tableHeadIds.size() * 10 * 3+"");
                }else {
                    electricCQuantity = Long.parseLong(tableHeadIds.size() * 3+"");
                }
            }
            DataMaintenance dataMaintenance = dataMaintenanceMapper.selectOne(new QueryWrapper<DataMaintenance>().eq("dky_code", tableHeads.get(i).getObjectId()));
            if (dataMaintenance != null && dataMaintenance.getNrCode() != null) {
                QueryWrapper<CalResultAll> craqw = new QueryWrapper<>();
                craqw.select("SUM(MOLECULE) AS MOLECULE");
                craqw.eq("parent_id_tree", treeId);
                craqw.eq("object_id", dataMaintenance.getNrCode());
                craqw.eq("parent_id_index", "1001");
                craqw.notIn("datasource", "0021990101");
                CalResultAll calResultAll = calResultAllMapper.selectOne(craqw);
                if (calResultAll != null && calResultAll.getMolecule() != null) {
                    electricCQuantity = Long.parseLong(calResultAll.getMolecule());
                }
            }
            sum = electricPower + electricCQuantity;
            generalizeVerseTwo.append(sum).append("个资产（").append(tableHeads.get(i).getAssetTypeNames().replaceAll(",", "、"));
            generalizeVerseTwo.append(electricPower).append("个资产；");
            generalizeVerseTwo.append("电量").append(electricCQuantity).append("个资产）");
            if(i != tableHeads.size()-1) {
                generalizeVerseTwo.append("、");
            }else {
                generalizeVerseTwo.append("。");
            }
        }
        return CompletableFuture.completedFuture(generalizeVerseTwo);
    }

}
